/*
 *  Rule.h
 *  NLParserDemo
 *
 *  Created by PH on 16.9.10.
 *  Copyright 2010 Petr Homola. All rights reserved.
 *
 */

#ifndef NLP_RULE_H_
#define NLP_RULE_H_

#include "global.h"
#include <string>
#include <iostream>
#include <vector>
#include "AVM.h"
#include "ListParser.h"
#include "Phrase.h"

namespace nlp {
	
	using namespace std;
#ifdef TR1
	using namespace std::tr1;
#endif
	
	class Phrase;
	
	class Rule {
		
	private:
		BLOCKVAR(block, AVM*, vector<Phrase*>*);
		
	public:
		Rule(BLOCKVAR(_block, AVM*, vector<Phrase*>*)) {
#ifdef __BLOCKS__
			block = Block_copy(_block);
#else
			block = _block;
#endif
		}
        
        Rule(const ListElement& el) {
            auto premise = el.getList()[0];
            auto actions = el.getList()[1];
            int arity = premise.getList().size();
            //cout << "Arity: " << arity << endl;
            auto _block = BLOCKRET(AVM*, &)(vector<Phrase*>* phrases) BLOCKBODY(AVM*) {
            //auto _block = BLOCKRET(AVM*)(vector<Phrase*>* phrases) BLOCKBODY(AVM*) {
                if (phrases->size() == arity) {
                    int pos = 0;
                    for (Phrase* phrase : *phrases) {
                        auto avm = phrase->getAvm();
                        for (const auto& condition : premise.getList()[pos].getList()) {
                            auto op = *(condition.getList()[0].getText());
                            //cout << "Op: " << op << endl;
                            if (op == "=") {
                                auto attr = *(condition.getList()[1].getText());
                                auto val = *(condition.getList()[2].getText());
                                if (!(avm->get(attr).getString() == val)) return nullptr;
                            }
                        }
                        pos++;
                    }
                    AVM* newAvm;
                    for (const auto& action : actions.getList()) {
                        auto op = *(action.getList()[0].getText());
                        //cout << op << endl;
                        if (op == "head") {
                            auto arg1 = *(action.getList()[1].getText());
                            int pos = atoi(arg1.c_str()) - 1;
                            newAvm = new AVM((*phrases)[pos]->getAvm());
                        } else if (op == "subord") {
                            auto arg1 = *(action.getList()[1].getText());
                            auto arg2 = *(action.getList()[2].getText());
                            int pos = atoi(arg2.c_str()) - 1;
                            newAvm->put(arg1, (*phrases)[pos]->getAvm());
                        }
                    }
                    return newAvm;
                }
                return nullptr;
            };
#ifdef __BLOCKS__
			block = Block_copy(_block);
#else
			block = _block;
#endif
        }
			 
		~Rule() {
#ifdef __BLOCKS__
			Block_release(block);
#endif
			//cout << "Rule dealloced" << endl;
		}
		
		AVM* apply(vector<Phrase*>* phrases) const {
			return block(phrases);
		}
		
	};
	
}

#endif
